#include "LogicRoomModule.h"
#include "LogicService.h"

#include "base/core/com_define.h"
#include "base/core/os/time.h"
#include "base/core/Profiler.h"
#include "Common/Utility/ServerTime.h"
#include "ProtoBuffer/AllProtocol.h"
#include "Access/CharacterDataSet.h"
#include "Character/PlayerMgr.h"
#include "Common/TableData/RoleBornCfg.h"
#include "Common/TableData/ItemItemCfg.h"
#include "Common/TableData/EquipEquipCfg.h"
#include "Common/TableData/RoleExpCfg.h"
#include "Common/Item/ItemMgr.h"
#include "Common/Utility/AccountUtility.h"
#include "Common/RoomDefine.h"
#include "Duplicate/DuplicateMgr.h"

#ifdef _MSC_VER
#pragma warning(disable:4100)
#pragma warning(disable:4244)
#pragma warning(disable:4102)
#endif

using namespace ProtoBuf;


LogicRoomModule::LogicRoomModule()
{

}

LogicRoomModule::~LogicRoomModule()
{

}


bool LogicRoomModule::Init()
{
	IMessageDispatch *pMessageDispatch = g_GetLogicService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
	{
		return false;
	}
	pMessageDispatch->registerClientHandler(EMODULE_ID_ROOM, this);
	pMessageDispatch->registerServerHandler(EMODULE_ID_ROOM, this);

	return true;
}

void LogicRoomModule::UnInit()
{
	IMessageDispatch *pMessageDispatch = g_GetLogicService()->GetServiceMessageDispatch();
	if (nullptr == pMessageDispatch)
	{
		return;
	}
	pMessageDispatch->unregisterClientHandler(EMODULE_ID_ROOM);
	pMessageDispatch->unregisterServerHandler(EMODULE_ID_ROOM);
}

void LogicRoomModule::onClientMessage(uint32_t actionId, RECV_PACKAGE& package, uint64_t Id /* = 0 */)
{
	Player* pPlayer = (Player*)g_GetCreatureMgr()->GetPlayer(Id); // package.session->GetUserData().ptr;
	if (nullptr == pPlayer)
	{
		LogErrFmtPrint("[logic] LogicRoomModule : recv msg error : can not find player...  actionid:%d, id:%u  ", package.cmd,Id);
		return;
	}
	switch (actionId)
	{
	case CLIENT_TO_LOGIC_ROOM_LIST:
	{
		//房间列表
		RoomList(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_CREATE: //创建房间
	{
		CreateRoom(pPlayer,package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_SET_PWD: //设置密码
	{
		SetRoomPwd(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_JOIN:			//加入房间
	{
		JoinRoom(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_INVITE_FRIEND:	//邀请好友
	{
		InviteFriend(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_INVITE_REPLY:	//回复邀请
	{
		ReplyInvite(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_BE_LEAVE:	//请离房间
	{
		KickRoom(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_LEAVE:	//离开房间
	{
		LeaveRoom(pPlayer, package);
	}
	break;
	case CLIENT_TO_LOGIC_ROOM_AUTO_JOIN:	//自动加入
	{
		AutoJoin(pPlayer, package);
	}
	break;
	default:
		break;
	}
}

void LogicRoomModule::onServerMessage(uint32_t actionId, RECV_PACKAGE &package)
{
	switch (actionId)
	{
	case CENTER_TO_LOGIC_ROOM_CHAR_ROOM_NOTIFY:
		{
			CharRoomNotify(package);
		}
		break;
	}
}

//通知逻辑服更新玩家房间
void LogicRoomModule::CharRoomNotify(RECV_PACKAGE &package)
{
	CLRoom_CharRoomNotify notify;
	if (!notify.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] CLRoom_CharRoomNotify parse failed...");
		return;
	}
	CharIDType charId = notify.charid();
	uint32_t roomId = notify.roomid();
	int32_t isowner = notify.is_owner();
	Player *pPlayer = g_GetCreatureMgr()->GetPlayer(charId);
	if (nullptr != pPlayer)
	{
		uint32_t oldRoomId = pPlayer->GetAttr(C_ROOM_ID);
		pPlayer->SetRoomAttr(roomId, isowner);
		//
		if (notify.notify_dup())
		{
			if (oldRoomId > 0 && roomId <= 0) //离开房间
			{
				//副本离开房间处理
				g_GetDuplicateMgr()->OnLeaveRoom(charId, pPlayer->GetSceneId());
			}
		}
	}
	else
	{
		LogErrFmtPrint("[logic] LogicRoomModule::CharRoomNotify can not find player : cid:%lu, roomid:%u, is_ownerid:%d ", charId, roomId, isowner);
	}
}

//房间列表
void LogicRoomModule::RoomList(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_ListReq req;
	if (!req.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_ListReq parse failed...");
		return;
	}
	uint32_t dupId = req.dup_id();
	int32_t ret = RET_SUCCESS;
	if (pPlayer->GetAttr(C_ROOM_ID) > 0)
	{
		//已经在房间中
		ret = RET_ROOM_ALREADY_JOIN;
	}
	else if (pPlayer->GetAttr(C_DUPLICATE_ID) > 0)
	{
		//已经在副本中
		ret = RET_DUPLICATE_ALREAY_IN;
	}
	else
	{
		const DuplicateDuplicateCfgInfo *pcfg = g_GetDuplicateDuplicateCfgTable()->GetDuplicateDuplicateCfgInfo(dupId);
		if (nullptr == pcfg)
		{
			ret = RET_FAIL;
		}
	}

	if (RET_SUCCESS == ret)
	{

		LCRoom_List lstReq;
		lstReq.set_dupid(dupId);
		lstReq.set_charid(pPlayer->GetCid());
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_LIST, &lstReq);
	}
	else
	{
		Room_ListRsp rsp;
		rsp.set_retcode(ret);
		rsp.set_dup_id(dupId);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_LIST, &rsp);
	}

}
//创建房间
void LogicRoomModule::CreateRoom(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_CreateReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_CreateReq parse failed...");
		return;
	}
	if (req.pwd_size() > 0 && req.pwd_size() != ROOM_MAX_PAWD_LEN)
	{
		return;
	}
	uint32_t dupId = req.dup_id();
	Part *part = pPlayer->GetPart(PART_DUPLICATE);
	if (nullptr == part)
	{
		return;
	}
	LCRoom_CreateRoom createReq;
	int32_t ret = RET_SUCCESS;
	if (pPlayer->GetAttr(C_ROOM_ID) > 0 )
	{
		//已经在房间中
		ret = RET_ROOM_ALREADY_JOIN;
	}
	else if (pPlayer->GetAttr(C_TEAM_ID) > 0)
	{
		//已经在队伍中
		ret = RET_TEAM_ALREADY_JOIN;
	}
	else if (pPlayer->GetAttr(C_DUPLICATE_ID) > 0)
	{
		//已经在副本中
		ret = RET_DUPLICATE_ALREAY_IN;
	}
	else
	{
		//校验密码格式
		int32_t isize = req.pwd_size();
		if (isize > 0)
		{
			if (isize < ROOM_MAX_PAWD_LEN)
			{
				LogErrFmtPrint("[logic] Room_CreateReq isize < ROOM_MAX_PAWD_LEN...cid:%lu, isize:%d,dupid:%u ", pPlayer->GetCid(), isize, dupId);
				ret = RET_ROOM_PWD_FORMAT_ERROR;
			}
			else
			{
				for (int32_t i = 0; i < isize; ++i)
				{
					int32_t ipwd = req.pwd(i);
					if (ipwd < 0 || ipwd > 9)
					{
						ret = RET_ROOM_PWD_FORMAT_ERROR;
						break;
					}
					createReq.add_pwd(ipwd);
				}
			}
		}
		if (RET_SUCCESS == ret)
		{
			ret = part->CanEnterDup(dupId);
		}		
	}
	
	if (RET_SUCCESS == ret)
	{
		//通知中心服
		createReq.set_charid(pPlayer->GetCid());
		createReq.set_dupid(dupId);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_CREATE, &createReq);
	}
	else
	{
		Room_CreateRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_CREATE, &rsp);
	}
}
//设置密码
void LogicRoomModule::SetRoomPwd(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_SetPwdReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_SetPwdReq parse failed...");
		return;
	}
	int32_t itype = req.type();// 1 设置，2 取消
	if (itype != 1 && itype != 2)
	{
		return;
	}
	LCRoom_SetPwd setReq;
	int32_t ret = RET_SUCCESS;
	if (pPlayer->GetAttr(C_ROOM_ID) <= 0)
	{
		//没有加入房间
		ret = RET_ROOM_NOT_JOIN;
	}
	else if (!pPlayer->GetAttr(C_ROOM_LEADER_ID))
	{
		//非房主
		ret = RET_ROOM_NOT_OWNER;
	}
	else
	{
		if (1 == itype)
		{
			if (req.pwd_size() != ROOM_MAX_PAWD_LEN)
			{
				return;
			}
			for (int32_t i = 0; i < ROOM_MAX_PAWD_LEN; ++i)
			{
				int32_t ipwd = req.pwd(i);
				if (i < 0 || i > 9)
				{
					ret = RET_ROOM_PWD_FORMAT_ERROR;
					break;
				}
				setReq.add_pwd(ipwd);
			}
		}
	}
	
	if (RET_SUCCESS == ret)
	{
		setReq.set_type(itype);
		setReq.set_charid(pPlayer->GetCid());
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_SET_PWD, &setReq);
	}
	else
	{
		Room_SetPwdRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_SET_PWD, &rsp);
	}
}
//加入房间
void LogicRoomModule::JoinRoom(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_JoinReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_JoinReq parse failed....");
		return;
	}
	if (req.pwd_size() > 0 && req.pwd_size() != ROOM_MAX_PAWD_LEN)
	{
		return;
	}
	LCRoom_Join joinReq;
	int32_t ret = RET_SUCCESS;
	uint32_t roomId = req.room_id();
	uint32_t dupId = req.dup_id();
	if (pPlayer->GetAttr(C_ROOM_ID) > 0)
	{
		if ((uint32_t)pPlayer->GetAttr(C_ROOM_ID) != roomId)
		{
			//已经加入其它房间
			ret = RET_ROOM_ALREADY_JOIN_OTHER;
		}
		else
		{
			//已经加入房间
			ret = RET_ROOM_ALREADY_JOIN;
		}
	}
	else if (pPlayer->GetAttr(C_TEAM_ID) > 0)
	{
		//已经加入队伍
		ret = RET_TEAM_ALREADY_JOIN;
	}
	else if (pPlayer->GetAttr(C_DUPLICATE_ID) > 0)
	{
		//已经在副本中
		ret = RET_DUPLICATE_ALREAY_IN;
	}
	else
	{
		Part *part = pPlayer->GetPart(PART_DUPLICATE);
		if (nullptr != part)
		{
			ret = part->CanEnterDup(dupId);
			if (RET_SUCCESS == ret)
			{
				int32_t isize = req.pwd_size();
				if (isize > 0)
				{
					for (int32_t i = 0; i < ROOM_MAX_PAWD_LEN; ++i)
					{
						int32_t ipwd = req.pwd(i);
						if (ipwd < 0 || ipwd > 9)
						{
							ret = RET_ROOM_PWD_FORMAT_ERROR;
							break;
						}
						joinReq.add_pwd(ipwd);
					}
				}
			}
		}
		else
		{
			ret = RET_FAIL;
		}
	}
	
	if (RET_SUCCESS == ret)
	{
		joinReq.set_charid(pPlayer->GetCid());
		joinReq.set_roomid(roomId);
		joinReq.set_dup_id(dupId);
		if(!g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_JOIN, &joinReq))
		{
			LogErrFmtPrint("[logic] LogicRoomModule::JoinRoom....SendDataToCenter failed...charid:%u, roomId:%u ", pPlayer->GetCid(), roomId);
		}
	}
	else
	{
		Room_JoinRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_JOIN, &rsp);
	}
	
}
//邀请好友
void LogicRoomModule::InviteFriend(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_InviteReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_InviteReq parse failed...");
		return;
	}
	CharIDType frdCid = req.friend_cid();
	CharIDType cid = pPlayer->GetCid();
	if (frdCid == cid)
	{
		return;
	}
	int32_t ret = RET_SUCCESS;
	if (pPlayer->GetAttr(C_ROOM_ID) <= 0)
	{
		//没有加入房间
		ret = RET_ROOM_NOT_JOIN;
	}
	else if (!pPlayer->GetAttr(C_ROOM_LEADER_ID))
	{
		//不是房主
		ret = RET_ROOM_NOT_OWNER;
	}
	else if (pPlayer->GetAttr(C_DUPLICATE_ID) > 0)
	{
		//已经在副本中
		ret = RET_DUPLICATE_ALREAY_IN;
	}
	if (RET_SUCCESS == ret)
	{
		LCRoom_InviteFriend inviteReq;
		inviteReq.set_charid(pPlayer->GetCid());
		inviteReq.set_friend_cid(frdCid);
		if(!g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_INVITE_FRIEND, &inviteReq))
		{
			LogErrFmtPrint("[logic] LogicRoomModule::InviteFriend....SendDataToCenter failed...charid:%u, frdCid:%u ", cid, frdCid);
		}
	}
	else
	{
		Room_InviteRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_INVITE_FRIEND, &rsp);
	}
}
//回复邀请
void LogicRoomModule::ReplyInvite(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_ReplyInviteReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_ReplyInviteReq parse failed...");
		return;
	}
	if (req.pwd_size() > 0 && req.pwd_size() != ROOM_MAX_PAWD_LEN)
	{
		LogErrFmtPrint("[logic] LogicRoomModule::ReplyInvite....req.pwd_size() > 0 && req.pwd_size() != ROOM_MAX_PAWD_LEN...");
		return;
	}
	int32_t reply = req.reply(); // 1 同意，2 拒绝
	uint32_t roomId = req.room_id();
	uint32_t dupId = req.dup_id();
	if (1 != reply && 2 != reply)
	{
		LogErrFmtPrint("[logic] LogicRoomModule::ReplyInvite....1 != reply && 2 != reply...reply:%d ", reply);
		return;
	}
	LCRoom_ReplyInvite replyReq;
	int32_t ret = RET_SUCCESS;
	if (1 == reply)
	{
		if (pPlayer->GetAttr(C_ROOM_ID) > 0)
		{
			//已经加入房间
			ret = RET_ROOM_ALREADY_JOIN;
		}
		else if (pPlayer->GetAttr(C_DUPLICATE_ID) > 0)
		{
			//已经在副本中
			ret = RET_DUPLICATE_ALREAY_IN;
		}
		else if (pPlayer->GetAttr(C_TEAM_ID) > 0)
		{
			//已经加入队伍
			ret = RET_TEAM_ALREADY_JOIN;
		}
		else
		{
			Part *part = pPlayer->GetPart(PART_DUPLICATE);
			if (nullptr != part)
			{
				ret = part->CanEnterDup(dupId);
				if (RET_SUCCESS == ret)
				{
					int32_t isize = req.pwd_size();
					if (isize > 0)
					{
						for (int32_t i = 0; i < ROOM_MAX_PAWD_LEN; ++i)
						{
							int32_t ipwd = req.pwd(i);
							if (i < 0 || i > 9)
							{
								ret = RET_ROOM_PWD_FORMAT_ERROR;
								break;
							}
							replyReq.add_pwd(ipwd);
						}
					} // end of if (isize > 0)
				}
			}
			else
			{
				ret = RET_FAIL;
			}
		}
	} // end of if (1 == reply)

	if (RET_SUCCESS == ret)
	{
		replyReq.set_charid(pPlayer->GetCid());
		replyReq.set_reply(reply);
		replyReq.set_room_id(roomId);
		replyReq.set_dup_id(dupId);
		if (!g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_INVITE_REPLY, &replyReq))
		{
			LogErrFmtPrint("[logic] LogicRoomModule::ReplyInvite....SendDataToCenter failed...charid:%u, roomid:%u ", pPlayer->GetCid(),roomId);
		}
	}
	else
	{
		Room_ReplyInviteRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_INVITE_REPLY, &rsp);
	}

}
//请离房间
void LogicRoomModule::KickRoom(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_KickReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_KickReq parse failed....");
		return;
	}
	CharIDType kickCid = req.cid();
	Player *pKickPlayer = g_GetCreatureMgr()->GetPlayer(kickCid);
	if (nullptr == pKickPlayer)
	{
		return;
	}
	CharIDType cid = pPlayer->GetCid();
	int32_t ret = RET_SUCCESS;
	if (kickCid == cid)
	{
		ret = RET_ROOM_NOT_KICK_SELF;
	}
	else if (pPlayer->GetAttr(C_ROOM_ID) <= 0)
	{
		ret = RET_ROOM_NOT_JOIN;
	}
	else if (pKickPlayer->GetAttr(C_ROOM_ID) <= 0)
	{
		ret = RET_ROOM_OTHER_NOT_JOIN;
	}
	else if (pKickPlayer->GetAttr(C_ROOM_ID) != pPlayer->GetAttr(C_ROOM_ID))
	{
		ret = RET_ROOM_NOT_IN_SAME_ROOM;
	}

	if (RET_SUCCESS == ret)
	{
		LCRoom_KickRoom kickReq;
		kickReq.set_charid(pPlayer->GetCid());
		kickReq.set_cid(kickCid);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_KICK, &kickReq);
	}
	else
	{
		Room_KickRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_KICK, &rsp);
	}
}
//离开房间
void LogicRoomModule::LeaveRoom(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_LeaveReq req;
	if (!req.ParseFromArray(package.dataAfterHead,package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_LeaveReq parse failed....");
		return;
	}
	int32_t ret = RET_SUCCESS;
	if (pPlayer->GetAttr(C_ROOM_ID) <= 0)
	{
		ret = RET_ROOM_NOT_JOIN;
	}
	
	if (RET_SUCCESS == ret)
	{
		LCRoom_LeaveRoom leaveReq;
		leaveReq.set_charid(pPlayer->GetCid());
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_LEAVE, &leaveReq);
	}
	else
	{
		Room_LeaveRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_LEAVE, &rsp);
	}
	
}
//自动加入
void LogicRoomModule::AutoJoin(Player *pPlayer, RECV_PACKAGE &package)
{
	Room_AutoJoinReq req;
	if (!req.ParseFromArray(package.dataAfterHead, package.sizeAfterHead))
	{
		LogErrFmtPrint("[logic] Room_AutoJoinReq parse failed....");
		return;
	}
	uint32_t dupId = req.dupid();
	int32_t ret = RET_SUCCESS;
	if (pPlayer->GetAttr(C_ROOM_ID) > 0)
	{
		ret = RET_ROOM_ALREADY_JOIN;
	}
	else if (pPlayer->GetAttr(C_TEAM_ID) > 0)
	{
		ret = RET_TEAM_ALREADY_JOIN;
	}
	else if (pPlayer->GetAttr(C_DUPLICATE_ID) > 0)
	{
		//已经在副本中
		ret = RET_DUPLICATE_ALREAY_IN;
	}
	else
	{
		Part *part = pPlayer->GetPart(PART_DUPLICATE);
		if (nullptr == part)
		{
			ret = RET_FAIL;
		}
		else
		{
			ret = part->CanEnterDup(dupId);
		}
	}
	if (RET_SUCCESS == ret)
	{
		LCRoom_AutoJoin autoReq;
		autoReq.set_charid(pPlayer->GetCid());
		autoReq.set_dupid(dupId);
		g_GetLogicService()->SendDataToCenter(EMODULE_ID_ROOM, LOGIC_TO_CENTER_ROOM_AUTO_JOIN, &autoReq);
	}
	else
	{
		Room_AutoJoinRsp rsp;
		rsp.set_retcode(ret);
		pPlayer->SendDataToClientEx(EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_AUTO_JOIN, &rsp);
	}
}
